/* Parsing of expressions. */

#include "defs.h"
#include "data.h"
#include "decl.h"

/*
 * Operator precedence for each token.
 */
static int OpPrec[] = {
    0,                  /* T_EOF */
    10, 10,             /* T_PLUS, T_MINUS */
    20, 20,             /* T_STAR, T_SLASH */
    30, 30,             /* T_EQ, T_NE */
    40, 40, 40, 40      /* T_LT, T_GT, T_LE, T_GE */
};

/*
 * Check that we have a binary operator and
 * return its precedence.
 */
static int op_precedence(int token_type)
{
    int prec;

    prec = OpPrec[token_type];
    if (prec == 0) {
        fprintf(stderr, "syntax error on line %d, token %d\n", Line, token_type);
        exit(1);
    }
    return prec;
}

/*
 * Convert a binary operator token into an AST operation.
 * We rely on a 1:1 mapping from token to AST operation.
 */
int arithop(int tok)
{
    if (tok > T_EOF && tok < T_INTLIT)
        return tok;
    fatald("Syntax error, token", tok);
}

/*
 * Parse a primary factor and return an 
 * AST node representing it.
 */
static struct ASTnode *primary(void)
{
    struct ASTnode *node;
    int id;

    switch (Token.token) {
    case T_INTLIT:
        /* for an INTLIT token, make a leaf AST node for it */
        if (Token.intvalue >= 0 && Token.intvalue <= 255)
            node = mkastleaf(A_INTLIT, P_CHAR, Token.intvalue);
        else
            node = mkastleaf(A_INTLIT, P_INT, Token.intvalue);
        break;

    case T_IDENT:
        /* check that this identifier exists */
        if ((id = findglob(Text)) == -1)
            fatals("Unknown variable", Text);

        /* make a leaf AST node for it */
        node = mkastleaf(A_IDENT, Gsym[id].type, id);
        break;

    default:
        fatald("Syntax error, token", Token.token); 
    }

    /* scan in the next token and return the leaf node */
    scan(&Token);
    return node;
}

/*
 * Return an AST tree whose root is a binary operator.
 * Parameter ptp is the previous token's precedence.
 */
struct ASTnode *binexpr(int ptp)
{
    struct ASTnode *left, *right;
    int token_type, left_type, right_type;

    left = primary();   /* get the integer literal on the left */
    token_type = Token.token;
    /* if we hit a semicon or ')', return just the left node */
    if (token_type == T_SEMI || token_type == T_RPAREN)
        return left;    

    while (op_precedence(token_type) > ptp) {
        scan(&Token);   /* fetch in the next integer literal */

        right = binexpr(OpPrec[token_type]);    /* recursively call  */

        left_type = left->type;
        right_type = right->type;
        if (!type_compatible(&left_type, &right_type, 0))
            fatal("Incompatible types");

        /* widen if necessary */
        if (left_type) left = mkastunary(A_WIDEN, right->type, left, 0);
        if (right_type) right = mkastunary(A_WIDEN, left->type, right, 0);

        left = mkastnode(arithop(token_type), left->type, left, NULL, right, 0);

        token_type = Token.token;
        if (token_type == T_SEMI || token_type == T_RPAREN)
            return left;    /* if no token left, return just the left node */
    }

    return left;
}
